package xyz.bali16.module.article.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import com.gitee.starblues.spring.MainApplicationContext;
import com.gitee.starblues.spring.SpringBeanFactory;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;
import xyz.bali16.application.core.exception.BusinessException;
import xyz.bali16.application.core.model.UserVo;
import xyz.bali16.application.core.utils.AuthUtils;
import xyz.bali16.application.core.utils.SensitiveFilter;
import xyz.bali16.application.core.utils.TimeUtil;
import xyz.bali16.application.entity.User;
import xyz.bali16.application.mapper.UserMapper;
import xyz.bali16.application.service.UserService;
import xyz.bali16.module.article.entity.Article;
import xyz.bali16.module.article.entity.Comment;
import xyz.bali16.module.article.mapper.ArticleMapper;
import xyz.bali16.module.article.mapper.CommentMapper;
import xyz.bali16.module.article.model.comment.CommentAddParam;
import xyz.bali16.module.article.model.comment.CommentPageParam;
import xyz.bali16.module.article.model.comment.CommentUpdateParam;
import xyz.bali16.module.article.service.CommentService;
import xyz.bali16.module.article.service.NotificationServiceCaller;
import xyz.bali16.module.notification.enums.NotificationTypeEnum;


import java.util.List;

import static xyz.bali16.application.constant.ForumConstant.ENTITY_TYPE_POST;


/**
 * 评论相关
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @AutowiredType(AutowiredType.Type.MAIN)
    @Autowired
    UserMapper userMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private ArticleMapper articleMapper;
    @AutowiredType(AutowiredType.Type.MAIN)
    @Autowired
    private SensitiveFilter sensitiveFilter;
    @Autowired
    private MainApplicationContext context;

    //@Autowired
    //@AutowiredType
    //private NotificationService notificationService;
    @Autowired
    private NotificationServiceCaller notificationServiceCaller;

    @Override
    public IPage<Comment> getPage(CommentPageParam param) {
        IPage<?> page = new Page<>(param.getCurrent(), param.getSize());
        return this.baseMapper.getPage(page, param);
    }


    /**
     * 根据评论目标查找高赞评论 这里需要redis
     *
     * @param entityType
     * @param entityId
     * @return
     */
    @Override
    public Comment getTopLikeCommentByEntity(Integer entityType, String entityId) {
        return null;
    }

    /**
     * 根据评论目标查找高回复评论
     *
     * @param entityId 帖子id
     * @return
     */
    @Override
    public Comment getTopAnswerCommentByEntity(String entityId) {
        return commentMapper.selectTopAnswerCommentByEntity(entityId);
    }

    /**
     * 查询评论的数量
     *
     * @param entityType
     * @param entityId
     * @return
     */
    @Override
    public Integer getCommentCount(Integer entityType, String entityId) {
        return commentMapper.selectCountByEntity(entityType, entityId);
    }

    /**
     * 查询某个用户的评论/回复数量
     *
     * @param userId
     * @return
     */
    @Override
    public Integer getUserCommentCount(String userId) {
        return commentMapper.selectCommentCountByUserId(userId);
    }

    /**
     * 添加评论（需要事务管理）
     *
     * @param param
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    @Override
    public void addComment(CommentAddParam param) throws Exception {
        Comment comment = new Comment();
        BeanUtils.copyProperties(param, comment);
        if (comment == null) {
            throw new IllegalArgumentException("参数不能为空");
        }
        String username = AuthUtils.getCurrentUsername();
        if (!StringUtils.isBlank(username)) {
            User user = userMapper.getUserByUsername(username);
            if (user == null) {
                throw new BusinessException("发帖用户信息不正确");
            }
            comment.setUserId(user.getUserId());
        }
        // Html 标签转义
        comment.setContent(HtmlUtils.htmlEscape(comment.getContent()));
        // 敏感词过滤
        comment.setContent(sensitiveFilter.filter(comment.getContent()));
        comment.setGmtCreated(TimeUtil.getNowTimeToSeconds());

        // 添加评论
        save(comment);
        //SpringBeanFactory factory = context.getSpringBeanFactory();
        //NotificationService notificationService = factory.getBean(NotificationService.class);
        // 更新帖子的评论数量
        if (comment.getEntityType() == ENTITY_TYPE_POST) {
            Integer count = commentMapper.selectCountByEntity(comment.getEntityType(), comment.getEntityId());
            updateArticleCommentCount(comment.getEntityId(), count);
            Article article = articleMapper.selectById(comment.getEntityId());

            SpringBeanFactory factory = context.getSpringBeanFactory();
            UserService userService = factory.getBean(UserService.class);
            User user = userService.getById(article.getUserId());
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user, userVo);
            article.setAuthor(userVo);
            // 排除自己对自己进行回复的行为
            if (!article.getAuthor().getUserId().equals(comment.getUserId())) {
                notificationServiceCaller.createNotify(comment.getUserId(), article.getAuthor().getUserId(), username, username + "对 \" " + article.getTitle() + " \" 进行了回复", NotificationTypeEnum.REPLY_QUESTION, article.getId());
            }
        } else {
            // 针对个人回帖评论
            if (!comment.getEntityId().equals(comment.getUserId())) { // 第一层的回复
                String outerId = null;
                Article article = articleMapper.selectById(comment.getEntityId());
                if(article!=null){
                    outerId = article.getId();
                }else{
                    Comment comment2 = commentMapper.selectById(comment.getEntityId());
                    if(comment2!=null){
                        outerId = comment2.getEntityId();
                    }
                }
                notificationServiceCaller.createNotify(comment.getUserId(), comment.getTargetId(), username, username + "对你的回复进行了评论", NotificationTypeEnum.REPLY_COMMENT, outerId);
            }
        }

    }


    @Override
    public void updateComment(CommentUpdateParam param) throws Exception {
        Preconditions.checkNotNull(param, "CommentUpdateParam 参数不能为为空");
        Comment comment = new Comment();
        BeanUtils.copyProperties(param, comment);
        updateById(comment);
    }

    @Override
    public void delete(String commentId) throws Exception {
        if (commentId == null) {
            return;
        }
        Wrapper<Comment> wrapper = Wrappers.<Comment>lambdaQuery().eq(Comment::getTargetId, commentId);
        // 移除所有子评论
        List<Comment> child_comments = commentMapper.selectList(wrapper);
        for (Comment comment : child_comments) {
            removeById(comment.getId());
        }

        removeById(commentId);
    }

    @Override
    public void updateArticleCommentCount(String articleId, Integer commentCount) {
        commentMapper.updateArticleComment(articleId, commentCount);
    }

    @Override
    public Integer getYesterdayCount() {
        DateTime yesterday = DateUtil.yesterday();
        return this.lambdaQuery()
                .ge(Comment::getGmtCreated,yesterday)
                .eq(Comment::getStatus,  1)
                .count();
    }

    @Override
    public Integer countComment() {
        return lambdaQuery().select(Comment::getId).count();
    }

}
